/*
 * Copyright (c) 2009 DeledImporter
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 *
 * * Neither the name of 'Pyro Games' nor the names of its contributors 
 *   may be used to endorse or promote products derived from this software 
 *   without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package net.pyrogames.deled.geometry;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.ArrayList;

import net.pyrogames.deled.material.DXSMaterial;
import net.pyrogames.deled.math.DXSVector2f;
import net.pyrogames.deled.math.DXSVector3f;

/**
 * Fundamental primitive class, represents just about everything in
 * a DeleD scene that is supposed to have geometry. This class
 * also contains convienance methods to supply its data in java.nio buffers.
 * 
 * @author Nicholas Woodfield
 *
 */
public class DXSPrimitive extends DXSSpatial {
	/** 
	 * Original vertex list, used for vertex ID look ups so we don't have
	 * to parse through the polygon list.
	 */
	public DXSVector3f[] vertices;
	/** Polygon list, all the faces (or triangles) that belong to this prim */
	public ArrayList<DXSPoly> polys;
	/** The material associated with this primitive */
	public DXSMaterial material;
	
	public enum PolygonWind{
		/** Polygons whose vertices are specified in CCW order are front facing */
		ClockWise,
		/** Polygons whose vertices are specified in CCW order are front facing */
		CounterClockWise
	}
	
	public DXSPrimitive(String primName, int numVerts){
		super(primName);
		vertices = new DXSVector3f[numVerts];
		polys = new ArrayList<DXSPoly>();
	}
	
	/**
	 * Compiles a buffer that has every vertex in the primitive,
	 * in the order they are contained by the polygon ordering. So
	 * the first three belong to the first poly, second three belong to the
	 * second etc.
	 * 
	 * @param wind
	 * 		Set the Polygon Winding, either ClockWise or CounterClockWise
	 * @return
	 * 		FloatBuffer with the size of 9 * polys.size()
	 */
	public FloatBuffer createVertBuffer(PolygonWind wind){
        FloatBuffer buf = ByteBuffer.allocateDirect(4 * 9 * polys.size()).order(ByteOrder.nativeOrder()).asFloatBuffer();
        buf.clear();
        if(wind == PolygonWind.ClockWise){
            for(DXSPoly poly : polys){
            	for(int i = 0; i < 3 ; i++){
            		DXSVector3f v = poly.vertices.get(i);
            		buf.put(v.x).put(v.y).put(v.z);
            	}
            }
        } else if(wind == PolygonWind.CounterClockWise){
            for(DXSPoly poly : polys){
            	for(int i = 2; i >= 0 ; i--){
            		DXSVector3f v = poly.vertices.get(i);
            		buf.put(v.x).put(v.y).put(v.z);
            	}
            }
        }
        buf.flip();
        return buf;
	}
	
	/**
	 * Compiles a buffer that has every vertex texture coordinate in the 
	 * primitive, in the order they are contained by the polygon ordering. 
	 * So the first three belong to the first poly, etc.
	 * 
	 * @param wind
	 * 		Set the Polygon Winding, either ClockWise or CounterClockWise
	 * @return
	 * 		FloatBuffer with the size of 6 * polys.size()
	 */
	public FloatBuffer createTexBuffer(PolygonWind wind){
        FloatBuffer buf = ByteBuffer.allocateDirect(4 * 6 * polys.size()).order(ByteOrder.nativeOrder()).asFloatBuffer();
        buf.clear();
        if(wind == PolygonWind.ClockWise){
            for(DXSPoly poly : polys){
            	for(int i = 0; i < 2; i++){
            		DXSVector2f v = poly.texVerts.get(i);
            		buf.put(v.x).put(v.y);
            	}
            }
        } else if(wind == PolygonWind.CounterClockWise){
            for(DXSPoly poly : polys){
            	for(int i = 2; i >= 0; i--){
            		DXSVector2f v = poly.texVerts.get(i);
            		buf.put(v.x).put(v.y);
            	}
            }
        }
        buf.flip();
        return buf;
	}
	
	/**
	 * Compiles a buffer that has every vertex normal in the primitive,
	 * in the order they are contained by the polygon ordering. So
	 * the first three belong to the first poly, second three belong to the
	 * second etc.
	 * 
	 * @param wind
	 * 		Set the Polygon Winding, either ClockWise or CounterClockWise
	 * @return
	 * 		FloatBuffer with the size of 9 * polys.size()
	 */
	public FloatBuffer createNormalBuffer(PolygonWind wind){
        FloatBuffer buf = ByteBuffer.allocateDirect(4 * 9 * polys.size()).order(ByteOrder.nativeOrder()).asFloatBuffer();
        buf.clear();
        if(wind == PolygonWind.ClockWise){
            for(DXSPoly poly : polys){
            	for(int i = 0; i < 3; i++){
            		DXSVector3f v = poly.vertNormals.get(i);
            		buf.put(v.x).put(v.y).put(v.z);
            	}
            }
        } else if(wind == PolygonWind.CounterClockWise){
            for(DXSPoly poly : polys){
            	for(int i = 2; i >= 0; i--){
            		DXSVector3f v = poly.vertNormals.get(i);
            		buf.put(v.x).put(v.y).put(v.z);
            	}
            }
        }
        buf.flip();
        return buf;
	}
	
	/**
	 * Trivial, since our vertex/normal/texCoord buffers are compiled in the order
	 * that polygons are listed in the primitive, and each polygon is essentially
	 * a triangle. This just returns a buffer with 0,1,2,3,4,5,6...etc since
	 * the first three are always one poly and the second three are always another
	 * poly, second three belong to the second etc.
	 * 
	 * @return
	 * 		IntBuffer the size of 3*polys.size()
	 */
	public IntBuffer createIndexBuffer(){
		IntBuffer buf = ByteBuffer.allocateDirect(4 * 3 * polys.size()).order(ByteOrder.nativeOrder()).asIntBuffer();
		int indx = 0;
		for(int i = 0; i < polys.size(); i++){
			buf.put(indx);
			indx++;
			buf.put(indx);
			indx++;
			buf.put(indx);
			indx++;
		}
        buf.flip();
        return buf;
	}
}
